var __MODELS = {
	users: {
		name: 'users',
		fields: {
			id: {type: 'int', autoIncrement: true},
			username: {type: 'string', size: 100},
			password: {type: 'fstring', size: 40},
			email: {type: 'string', size: 100},
			roles: {type: 'string', size: 50, default: 'user'}
		},
		children: ['feedfolders'],
		rules: [],
		views: ['register','edit','view','import','login'],
		actions: ['register','edit','view','delete','import_opml','login','logout']
	},
	feedfolders: {
		name: 'feedfolders',
		fields: {
			id: {type: 'int', autoIncrement: true},
			user_id: {type: 'int', joinsTo: ['users','id']},
			label: {type: 'string', size: 100},
			order: {type: 'int'}
		},
		children: ['feeds'],
		rules: [],
		views: [],
		actions: ['add','rename','delete']
	},
	feeds: {
		name: 'feeds',
    fields: {
			id: {type: 'int', autoIncrement: true},
			image: {type: 'string', size: 255},
			home_url: {type: 'string', size: 255},
			folder_id: {type: 'int', joinsTo: ['feedfolders','id']},
			text: {type: 'text'},
			title: {type: 'string'},
			xml: {type: 'string', index: true},
			html: {type: 'string'},
			updated: {type: 'timestamp'}
		},
		children: ['entries'],
		rules: [],
		views: [],
		actions: ['add','delete','pull']
	},
	entries: {
		name: 'entries',
		singular: 'entry',
		fields: {
			id: {type: 'int', autoIncrement: true},
			feed_id: {type: 'int', joinsTo: ['feeds','id']},
			title: {type: 'string', size: 200},
			link: {type: 'string', size: 255},
			description: {type: 'text'},
			guid: {type: 'string', size: 255, index: true},
      pub_date: {type: 'timestamp'},
			read: {type: 'bool', default: 0}
		},
		children: [],
		rules: [],
		views: [],
		actions: ['add','delete','mark_read']
	}
};

function rule() {
	print('\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n');
} // rule()

function fail(m) {
	print("FAIL: " + m);
	return false;
} // fail()


function underscoreToCamelCase(n) {
	var name = '';
	
	for (var i = 0; i < n.length; i++) {
		if (i == 0) {
			name += n.substr(i, 1).toUpperCase();
		} else if (n.substr(i, 1) == '_') {
			i++;
			name += n.substr(i, 1).toUpperCase();
		} else {
			name += n.substr(i, 1).toLowerCase();
		}
	}
	
	return name;
} // underscoreToCamelCase()

function validateModel(m) {
	rule();
	
	print('Validating Model...');
	
	
	if (m.hasOwnProperty('name')) {
		print("Model Name: " + m.name);
	} else {
		return fail("No model name specified!");
	}
	
	if (m.hasOwnProperty('singular')) {
		print('Singular: ' + m.singular);
	} else {
		if (m.name.substr(-1).toLowerCase() == 's') {
			m.singular = m.name.substr(0, m.name.length -1);
			print("Assumed Singular: " + m.singular);
		} else {
			return fail("No singular defined!");
		}
	}
	
	if (m.hasOwnProperty('fields')) {
		var flds = m['fields'];
		var fld_info = "  FIELDS:\n";
		var fld_cnt = 0;
		for (var f in flds) {
			if (flds.hasOwnProperty(f)) {
				fld_cnt++;
				fld_info += "    " + f + " : " + flds[f].type + '\n';
			}
		}
		
		if (fld_cnt > 0) {
			print(fld_info);
		} else {
			return fail("No fields specified");
		}
	} else {
		return fail("No fields specified!");
	}
	
	print('...Model Validated');
	rule();
	return true;
	
} // validateModel();

function genSQL(m) {
	//rule();
	//
	//print("Generating SQL for " +  m.name + "...\n");
	
	var fc = 0;
	
	var fl = [];
	var keys = [];
	
	var sql_code = '';
	
	for (var f in m.fields) {
		if (m.fields.hasOwnProperty(f)) {
			var ft = m.fields[f].type.toUpperCase();
			var ai = m.fields[f].autoIncrement === true ? ' AUTO_INCREMENT' : '';
			var sz = false;
			var nn = ' NOT NULL';
			var def = typeof m.fields[f].default !== 'undefined' ? ' DEFAULT "' + m.fields[f].default + '"' : false;
			
			if (f.toLowerCase() == 'id') {
				keys.push('  PRIMARY KEY (id)');
			} else if (f.toLowerCase().indexOf('_id') > 0) {
				keys.push('  INDEX ' + f.toLowerCase() + '_idx (' + f.toLowerCase() + ')');
			} else if (m.fields[f].index === true) {
				keys.push('  INDEX ' + f.toLowerCase() + '_idx (' + f.toLowerCase() + ')');
			}
			
			switch (ft.toLowerCase()) {
				case 'string':
					sz = 255;
					ft = 'VARCHAR';
					def = def === false ? ' DEFAULT ""' : '';
					break;
				case 'int':
					sz = 11;
					ft = 'INTEGER';
					def = def === false && m.fields[f].autoIncrement !== true ? ' DEFAULT "0"' : '';;
					break;
			  case 'fstring':
					sz = 25;
					ft = 'CHAR';
					def = def === false ? ' DEFAULT ""' : def;
					break;
				case 'text':
					sz = false;
					ft = 'TEXT';
					def = def === false ? ' DEFAULT ""' : def;
					break;
				case 'timestamp':
					sz = 11;
					ft = 'INTEGER';
					def = def === false ? ' DEFAULT "0"' : def;
					break;
			  case 'bool':
				case 'boolean':
					sz = false;
					ft = 'BOOL';
					def = def === false ? ' DEFAULT "0"' : def;
					break;
			}
			
			
			if (m.fields[f].hasOwnProperty('size')) {
				sz = m.fields[f].size;
			}
			
			if (m.fields[f].notNull === false) {
				nn = '';
			}
			
			if (m.fields[f].hasOwnProperty('default')) {
				def = ' DEFAULT "' + m.fields[f].default + '"';
			}
			
			if (sz !== false) {
				sz = '(' + sz + ')';
			} else {
				sz = '';
			}
			
			var entry = "  `" + f + "` " + ft + sz + nn + def + ai;
			fl.push(entry);
			fc++
		}
	}
	
	if (keys.length > 0) { fl.push(''); }
	
	sql_code += "DROP TABLE IF EXISTS " + m.name + ";\n";
	sql_code += "CREATE TABLE " + m.name + " (\n";
	sql_code += fl.join(",\n") + '\n';
	sql_code += keys.join(',\n') + '\n';
	sql_code += ") ENGINE=MyISAM DEFAULT CHARSET=latin1;\n\n\n";
	
	//print("\n\n...done");
	//rule();
	
	return sql_code;
} // genSQL()

function genModel(m) {

	//rule();
	//print('Generating model for ' + m.name + '...\n');
	
	var class_name = underscoreToCamelCase(m.singular);
	
	var mdl_code = '';
	mdl_code += '<?php\n\n';
	mdl_code += '// Place in ./app/models/' + class_name + '.php\n\n';
	mdl_code += 'class ' + class_name + ' extends AppModel {\n';
	mdl_code += '  var $name = "' + class_name + '";\n';
	
	var rel_code = '';
	
	if (m.hasOwnProperty('children')) {
		rel_code = '\n';
		rel_code += '  var $hasMany = array(\n';
		var relations = [];
		for (var i = 0; i < m.children.length; i++) {
			var child = m.children[i];
			var r = '';
			if (__MODELS.hasOwnProperty(child)) {
				r += '    "' + underscoreToCamelCase(__MODELS[child].name) + '" => array(\n';
				r += '      "className" => "' + underscoreToCamelCase(__MODELS[child].singular) + '",\n';
				r += '      "order" => "' + underscoreToCamelCase(child) + '.order DESC"\n';
				r += '    )';
			}
			relations.push(r);
		}
		if (relations.length > 0) {
			rel_code += relations.join(',\n') + '\n';
			rel_code += '  );\n';
		} else {
			rel_code = '';
		}
	}

  mdl_code += rel_code;	
	mdl_code += '} // class ' + class_name + '\n';
	mdl_code += '\n';
	mdl_code += '?>\n';
	
//	print(mdl_code);
	
//	print('\n\n...Model Generated');
//  print('\n\n...done');
//	rule();
	
	return mdl_code;
} // genModel()


function genController(m) {
	var ctl_code = '';
	ctl_code += '<?php\n\n';
	ctl_code += '// Place in ./app/controllers/' + m.name.toLowerCase() + '_controller.php\n\n';
	ctl_code += 'class ' + underscoreToCamelCase(m.name) + 'Controller extends AppController {\n\n';
	var cl_nm = underscoreToCamelCase(m.singular);
	
	for (var i = 0; i < m.actions.length; i++) {
		var act = m.actions[i];
		var params = '';
		var action_code = '';
		
		switch(act.toLowerCase()) {
			case 'add':
			case 'create':
			case 'register':
				action_code += '    if (!empty($this->data)) {\n';
				action_code += '      if ($this->' + cl_nm + '->save($this->data)) {\n';
				action_code += '        $this->Session->setFlash(\'Added\');\n';
				action_code += '        $this->redirect(array(\'action\'=>\'index\'));\n';
        action_code += '      } else {\n';
        action_code += '        $this->Session->setFlash(\'There was a problem with your section element\');\n';
        action_code += '      }\n';
				action_code += '    }\n';
				break;
			case 'edit':
			case 'rename':
				action_code += '    if (empty($this->data)) {\n';
				action_code += '      $this->data = $this->' + cl_nm + '->read(null, $id);\n';
				action_code += '    } else {\n';
				action_code += '      if ($this->' + cl_nm + '->save($this->data)) {\n';
				action_code += '        $this->Session->setFlash(\'Updated\');\n';
				action_code += '        $this->redirect(array(\'action\'=>\'view\', $id));\n'
				action_code += '      } else {\n'
				action_code += '        $this->Session->setFlash(\'Edit error\');\n'
				action_code += '      }\n'
				action_code += '    }\n';
				params = '$id = NULL';
				break;
			case 'delete':
				action_code += '    $this->' + cl_nm + '->delete($id);\n'
				action_code += '    $this->Session->setFlash("Deleted");\n';
				action_code += '    $this->redirect(array(\'action\'=>\'index\'));\n';
				params = '$id = NULL';
				break;
			case 'view':
				action_code = '    $this->set(\'' + m.singular.toLowerCase() + '\', $this->' + cl_nm + '->read(null, $id));\n';
				params = '$id = NULL';
				break;
			case 'moveup':
				params = '$id = NULL';
				break;
			case 'movedown':
			  params = '$id = NULL';
				break;
			case 'move':
			  params = '$id = NULL, $dir = NULL';
				break;
		  case 'index':
				action_code += '    $this->set(\'' + m.name.toLowerCase() + '\', $this->' + cl_nm + '->find(\'all\'));\n';
		}
		
		ctl_code += '  function ' + act + '(' + params + ') {\n';
		
		ctl_code += action_code;
		
		ctl_code += '  } // ' + act + '()\n\n';
	}
	
	ctl_code += '} // class ' + underscoreToCamelCase(m.name) + '\n\n';
	ctl_code += '?>\n\n';
	
	return ctl_code;
	
} // getController()

function process(o) {
	var ok_models = [];
	var sql = '';
	var models = '';
	var controllers = '';
	
	for(var prop in o) {
		if(o.hasOwnProperty(prop)) {
			if (validateModel(o[prop])) {
				ok_models.push(prop);
			}
		}
	}
	
	for(var i = 0; i < ok_models.length; i++) {
		var prop = ok_models[i];
		sql += genSQL(o[prop]);
		models += genModel(o[prop]);
		controllers += genController(o[prop]);
	}
	
	print(sql);
	rule();
	print(models);
	rule();
	print(controllers);
}

process(__MODELS);